From: Nicholas Wilson Date: Thu, 27 Aug 2026 15:52:16 +0000 (+0100) Subject: Backport of pcre2-10.48-Fix-compiler-integer-overflows.patch X-Git-Tag: archive/raspbian/10.46-1_deb13u2+rpi1^2~2 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=c4585fc0ad74c46381609a69a9a57d51064fa42d;p=pcre2.git Backport of pcre2-10.48-Fix-compiler-integer-overflows.patch Cherry-pick of ec9c286d5c10cf1c388b58a442ccefded42254fd Fix compiler integer overflows; see GHSA-fmgr-6ggq-9859 for details (cherry picked from commit 983158a222ec27a93ce678778f9343f7dfa35845) --- diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c index 0ffac89..78cc66a 100644 --- a/src/pcre2_compile.c +++ b/src/pcre2_compile.c @@ -6069,7 +6069,8 @@ for (;; pptr++) if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) { - if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code)) + if (*lengthptr > OFLOW_MAX || + OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code)) { *errorcodeptr = ERR20; /* Integer overflow */ return 0; @@ -8548,7 +8549,8 @@ for (;;) *reqcuflagsptr = reqcuflags; if (lengthptr != NULL) { - if (OFLOW_MAX - *lengthptr < length) + if (*lengthptr > MAX_PATTERN_SIZE || + MAX_PATTERN_SIZE - *lengthptr < length) { *errorcodeptr = ERR20; return 0; @@ -8571,6 +8573,19 @@ for (;;) { code = *codeptr + 1 + LINK_SIZE + skipunits; length += 1 + LINK_SIZE; + + /* Move the accumulated length into *lengthptr, providing the next call to + compile_branch with as much space in &length and &code as the first did. */ + + if (*lengthptr > MAX_PATTERN_SIZE || + MAX_PATTERN_SIZE - *lengthptr < length) + { + *errorcodeptr = ERR20; + cb->erroroffset = 0; + return 0; + } + *lengthptr += length; + length = 0; } else { @@ -10626,7 +10641,8 @@ if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */ #if defined SUPPORT_WIDE_CHARS PCRE2_ASSERT((cb.char_lists_size & 0x3) == 0); if (length > MAX_PATTERN_SIZE || - MAX_PATTERN_SIZE - length < (cb.char_lists_size / sizeof(PCRE2_UCHAR))) + BYTES2CU(cb.char_lists_size) > MAX_PATTERN_SIZE || + MAX_PATTERN_SIZE - length < BYTES2CU(cb.char_lists_size)) #else if (length > MAX_PATTERN_SIZE) #endif @@ -10650,11 +10666,36 @@ if (cb.char_lists_size != 0) /* Align to 32 bit first. This ensures the allocated area will also be 32 bit aligned. */ re_blocksize = (PCRE2_SIZE)CLIST_ALIGN_TO(re_blocksize, sizeof(uint32_t)); +#else + /* Already 32 bit aligned. */ #endif + + /* We have bounded the length and BYTES2CU(char_lists_size) to + MAX_PATTERN_SIZE units, however (with 32-bit code units) char_lists_size + in bytes could still be extremely close to (or greater than) SIZE_MAX, so + we require another overflow check. */ + + if (cb.char_lists_size > PCRE2_SIZE_MAX - re_blocksize) + { + errorcode = ERR20; + cb.erroroffset = 0; + goto HAD_CB_ERROR; + } + re_blocksize += cb.char_lists_size; } #endif +if (length > BYTES2CU(PCRE2_SIZE_MAX - re_blocksize)) + { + /* Given the current value of 2^30 for MAX_PATTERN_SIZE, this block is only + reachable when both PCRE2_CODE_UNIT_WIDTH >= 16 and sizeof(size_t) is + 32 bits. */ + errorcode = ERR20; + cb.erroroffset = 0; + goto HAD_CB_ERROR; + } + re_blocksize += CU2BYTES(length); if (re_blocksize > ccontext->max_pattern_compiled_length) @@ -10663,7 +10704,15 @@ if (re_blocksize > ccontext->max_pattern_compiled_length) goto HAD_CB_ERROR; } +if (sizeof(pcre2_real_code) > PCRE2_SIZE_MAX - re_blocksize) + { + errorcode = ERR20; + cb.erroroffset = 0; + goto HAD_CB_ERROR; + } + re_blocksize += sizeof(pcre2_real_code); + re = (pcre2_real_code *) ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); if (re == NULL) diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c index 0dd9e35..f3e7d1d 100644 --- a/src/pcre2_compile_class.c +++ b/src/pcre2_compile_class.c @@ -499,7 +499,7 @@ static const uint32_t char_list_starts[] = { static class_ranges * compile_optimize_class(uint32_t *start_ptr, uint32_t options, - uint32_t xoptions, compile_block *cb) + uint32_t xoptions, int *errorcodeptr, compile_block *cb) { class_ranges* cranges; uint32_t *ptr; @@ -536,12 +536,23 @@ PCRE2_ASSERT((range_list_size & 0x1) == 0); total_size = range_list_size + ((range_list_size >= 2) ? CHAR_LIST_EXTRA_SIZE : 0); +if (total_size > (PCRE2_SIZE_MAX - sizeof(class_ranges)) / sizeof(uint32_t)) + { + *errorcodeptr = ERR20; + cb->erroroffset = 0; + return NULL; + } cranges = cb->cx->memctl.malloc( sizeof(class_ranges) + total_size * sizeof(uint32_t), cb->cx->memctl.memory_data); -if (cranges == NULL) return NULL; +if (cranges == NULL) + { + *errorcodeptr = ERR21; + cb->erroroffset = 0; + return NULL; + } cranges->next = NULL; cranges->range_list_size = (uint16_t)range_list_size; @@ -1107,13 +1118,10 @@ if (utf) { if (lengthptr != NULL) { - cranges = compile_optimize_class(pptr, options, xoptions, cb); + cranges = compile_optimize_class(pptr, options, xoptions, errorcodeptr, cb); if (cranges == NULL) - { - *errorcodeptr = ERR21; return NULL; - } /* Caching the pre-processed character ranges. */ if (cb->next_cranges != NULL) @@ -1731,18 +1739,17 @@ if ((xclass_props & XCLASS_REQUIRED) != 0) *lengthptr += 1 + LINK_SIZE; #endif - cb->char_lists_size += char_lists_size; - - char_lists_size /= sizeof(PCRE2_UCHAR); + PCRE2_ASSERT(BYTES2CU(cb->char_lists_size) <= MAX_PATTERN_SIZE); - /* Storage space for character lists is included - in the maximum pattern size. */ - if (*lengthptr > MAX_PATTERN_SIZE || - MAX_PATTERN_SIZE - *lengthptr < char_lists_size) + if (char_lists_size > PCRE2_SIZE_MAX - cb->char_lists_size || + BYTES2CU(char_lists_size) > MAX_PATTERN_SIZE || + BYTES2CU(cb->char_lists_size) > MAX_PATTERN_SIZE - BYTES2CU(char_lists_size)) { *errorcodeptr = ERR20; /* Pattern is too large */ return NULL; } + + cb->char_lists_size += char_lists_size; } else { @@ -1765,6 +1772,8 @@ if ((xclass_props & XCLASS_REQUIRED) != 0) Each list is aligned to 32 bit with an optional unused 16 bit value at the beginning of the character list. */ + PCRE2_ASSERT(char_lists_size <= PCRE2_SIZE_MAX - cb->char_lists_size); + cb->char_lists_size += char_lists_size; data = (uint8_t*)cb->start_code - cb->char_lists_size;